/* See COPYRIGHT for copyright information. */

#include <inc/mmu.h>
#include <inc/memlayout.h>

# Shift Right Logical 
#define SRL(val, shamt)		(((val) >> (shamt)) & ~(-1 << (32 - (shamt))))


###################################################################
# The kernel (this code) is linked at address ~(KERNBASE + 1 Meg), 
# but the bootloader loads it at address ~1 Meg.
#	
# RELOC(x) maps a symbol x from its link address to its actual
# location in physical memory (its load address).	 
###################################################################

#define	RELOC(x) ((x) - KERNBASE)


.set CODE_SEL,0x8		# index of code seg within mygdt
.set DATA_SEL,0x10		# index of data seg within mygdt

#define MULTIBOOT_PAGE_ALIGN  (1<<0)
#define MULTIBOOT_MEMORY_INFO (1<<1)
#define MULTIBOOT_HEADER_MAGIC (0x1BADB002)
#define MULTIBOOT_HEADER_FLAGS (MULTIBOOT_MEMORY_INFO | MULTIBOOT_PAGE_ALIGN)
#define CHECKSUM (-(MULTIBOOT_HEADER_MAGIC + MULTIBOOT_HEADER_FLAGS))

###################################################################
# entry point
###################################################################

.text

# The Multiboot header
.align 4
.long MULTIBOOT_HEADER_MAGIC
.long MULTIBOOT_HEADER_FLAGS
.long CHECKSUM

.globl		_start
_start:
	movw	$0x1234,0x472			# warm boot

	# Clear the frame pointer register (EBP)
	# so that once we get into debugging C code,
	# stack backtraces will be terminated properly.
	movl	$0x0,%ebp			# nuke frame pointer

        # Set the stack pointer
	movl	$(RELOC(bootstacktop)),%esp

	#preserve the GRUB magic info
	push %eax
	push %ebx
	
	movl $(RELOC(init_paging)), %edx
	call %edx

	#okay...in theory, paging is ready to go, so enable paging
	
	mov $INITIAL_PDE, %eax
	mov %eax, %cr3
 
	mov %cr0, %eax
	or $0x80000000, %eax
	mov %eax, %cr0	

	#get the info back off the stack before we NEWK it!
	pop %ebx
	pop %eax
	
	# Perform a long jump to a symbol the linker has provided.  This
	# will move the program counter register into the address space
	# ArcanOS is linked to.
	
	ljmp	$CODE_SEL,$relocated
relocated:

	# Clear the frame pointer register (EBP)
	# so that once we get into debugging C code,
	# stack backtraces will be terminated properly.
	movl	$0x0,%ebp			# nuke frame pointer

        # Set the stack pointer
	movl	$(bootstacktop),%esp
	
	push %eax #push the multiboot magic number on the stack
	push %ebx #push the multipoot pointer on the stack
		
	# now to C code
	call	kernel_main

	# Should never get here, but in case we do, just spin.
spin:	jmp	spin

###################################################################
# boot stack
###################################################################
	.p2align	PGSHIFT		# force page alignment
	.globl		bootstack
bootstack:
	.space		KSTKSIZE
	.globl		bootstacktop   
bootstacktop:

###################################################################
# setup the GDT	
###################################################################
	.p2align	2		# force 4 byte alignment
mygdt:
	SEG_NULL				# null seg
	SEG(STA_X|STA_R, -KERNBASE, 0xffffffff)	# code seg
	SEG(STA_W, -KERNBASE, 0xffffffff)	# data seg
mygdtdesc:
	.word	0x17			# sizeof(mygdt) - 1
	.long	RELOC(mygdt)		# address mygdt

mygdt_flat:
	SEG_NULL				# null seg
	SEG(STA_X|STA_R, 0, 0xffffffff)	# code seg
	SEG(STA_W, 0, 0xffffffff)	# data seg
mygdtdesc_flat:
	.word	0x17			# sizeof(mygdt_flat) - 1
	.long	RELOC(mygdt_flat)		# address mygdt_flat
